package com.dreamoo.conf;

import com.dreamoo.common.annotation.EnumValue;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterFactory;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;

/**
 * @author 山顶洞人郑某
 * @className StringToEnumConverterFactory.java
 * @date 2025 05 08
 * 通用的字符串到枚举的转换器工厂
 */
public class StringToEnumConverterFactory implements ConverterFactory<String, Enum<?>> {

    private static final Map<Class<?>, Converter<String, ?>> CONVERTER_CACHE = new WeakHashMap<>();

    @Override
    public <T extends Enum<?>> Converter<String, T> getConverter(Class<T> targetType) {
        Converter<String, T> converter = (Converter<String, T>) CONVERTER_CACHE.get(targetType);
        if (converter == null) {
            converter = new StringToEnumConverter<>(targetType);
            CONVERTER_CACHE.put(targetType, converter);
        }
        return converter;
    }

    private static class StringToEnumConverter<T extends Enum<?>> implements Converter<String, T> {
        private final Class<T> enumType;
        private final Map<String, T> enumMap = new HashMap<>();
        private final Map<Integer, T> enumValueMap = new HashMap<>();
        private boolean hasEnumValue = false;

        public StringToEnumConverter(Class<T> enumType) {
            this.enumType = enumType;
            T[] enums = enumType.getEnumConstants();
            
            // 检查是否有@EnumValue注解的方法
            Method enumValueMethod = null;
            for (Method method : enumType.getDeclaredMethods()) {
                if (method.isAnnotationPresent(EnumValue.class)) {
                    enumValueMethod = method;
                    hasEnumValue = true;
                    break;
                }
            }
            
            // 构建映射关系
            for (T e : enums) {
                // 枚举名称映射
                enumMap.put(e.name().toLowerCase(), e);
                
                // 如果有EnumValue注解，还构建值到枚举的映射
                if (hasEnumValue && enumValueMethod != null) {
                    try {
                        Object value = enumValueMethod.invoke(e);
                        if (value instanceof Integer) {
                            enumValueMap.put((Integer) value, e);
                        }
                    } catch (Exception ex) {
                        // 忽略异常
                    }
                }
            }
        }

        @Override
        public T convert(String source) {
            if (source == null || source.isEmpty()) {
                return null;
            }
            
            // 尝试按枚举名称匹配
            String key = source.toLowerCase();
            T result = enumMap.get(key);
            
            // 如果没有匹配到名称，并且有EnumValue注解，尝试按值匹配
            if (result == null && hasEnumValue) {
                try {
                    Integer value = Integer.parseInt(source);
                    result = enumValueMap.get(value);
                } catch (NumberFormatException e) {
                    // 忽略转换异常
                }
            }
            
            return result;
        }
    }
} 